package com.gitee.jmash.rbac.grpc;

import com.crenjoy.proto.beanutils.ProtoBeanUtils;
import com.gitee.jmash.common.event.OperEvent;
import com.gitee.jmash.core.grpc.cdi.GrpcServerInterceptor;
import com.google.protobuf.MessageOrBuilder;
import com.google.protobuf.util.JsonFormat;
import io.grpc.ForwardingServerCallListener;
import io.grpc.Metadata;
import io.grpc.ServerCall;
import io.grpc.ServerCall.Listener;
import io.grpc.ServerCallHandler;
import io.grpc.ServerInterceptor;
import jakarta.annotation.Priority;
import jakarta.enterprise.event.Event;
import jakarta.inject.Inject;
import jmash.protobuf.FileBase64Req;
import jmash.protobuf.FileUploadReq;
import jmash.protobuf.FileWebUploadReq;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 操作日志.
 *
 * @author cgd
 *
 */
@GrpcServerInterceptor
@Priority(2100)
public class OperLogInterceptor implements ServerInterceptor {

  private static final Log log = LogFactory.getLog(OperLogInterceptor.class);

  /** 安全日志. */
  @Inject
  Event<OperEvent> event;

  @Override
  public <ReqT, RespT> Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers,
      ServerCallHandler<ReqT, RespT> next) {
    try {
      return new ContextualizedServerCallListener<>(next.startCall(call, headers), event,
          call.getMethodDescriptor().getFullMethodName());
    } catch (Throwable ex) {
      log.error("", ex);
      return next.startCall(call, headers);
    }
  }

  /**
   * 客户端请求处理过程各阶段信息打印.
   */
  private static class ContextualizedServerCallListener<ReqT>
      extends ForwardingServerCallListener.SimpleForwardingServerCallListener<ReqT> {

    String fullMethodName;

    Event<OperEvent> event;

    public ContextualizedServerCallListener(ServerCall.Listener<ReqT> delegate,
        Event<OperEvent> event, String fullMethodName) {
      super(delegate);
      this.fullMethodName = fullMethodName;
      this.event = event;
    }
    
    /** 忽略打印. */
    public boolean ignore(ReqT message) {
      if (message instanceof FileUploadReq) {
        return true;
      }
      if (message instanceof FileWebUploadReq) {
        return true;
      }
      if (message instanceof FileBase64Req) {
        return true;
      }
      return false;
    }

    @Override
    public void onMessage(ReqT message) {
      super.onMessage(message);
      String[] methods = fullMethodName.split("/");
      // 跳过查询请求日志记录.
      if (methods[1].startsWith("find")) {
        return;
      }
      // 获取租户.
      String tenant = null;
      try {
        tenant = ProtoBeanUtils.getSimpleProperty(message, "tenant");
      } catch (Exception ex) {
      }
      // 上传多次调用
      if (ignore(message)) {
        event.fireAsync(OperEvent.createNormal(tenant, methods[0], methods[1], "{}"));
        return;
      }
      // 一般请求记录请求内容.
      try {
        String context = JsonFormat.printer().print((MessageOrBuilder) message);
        if (context.length()<=1024) {
          event.fireAsync(OperEvent.createNormal(tenant, methods[0], methods[1], context));
        }else {
          event.fireAsync(OperEvent.createNormal(tenant, methods[0], methods[1], "{}"));
        }
      } catch (Exception ex) {
      }
    }
  }
}
